package com.flexcloudsdk.files;
import java.io.FileNotFoundException;

import java.io.IOException;
import java.util.logging.Logger;

import com.flexcloudsdk.files.CloudFileSystem;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileReadChannel;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.LockException;

public class CloudFile {
	private static final Logger log = Logger.getLogger(CloudFile.class.getName());
	private AppEngineFile cloudFile = null;
	private CloudFileSystem cloudFileSystem = null;
	private long pos;
	private String sourceClass;
	private String sourceMethod;

	public CloudFile() {
		log.info("CloudFile has been created by BlazeDS");
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		sourceClass = CloudFile.class.getName();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
	}

	public AppEngineFile  createRawFile(String name) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		log.info("Calling CloudFile.createRawFile: " + name);
		cloudFile = new AppEngineFile(name);
		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in createRawFile(CloudFileSystem, String) call, aborting");
			log.severe("Please call createNew or createRawFile call first!");
			return null;
		}
		return cloudFile;
	}
	
	public AppEngineFile createRawFile(CloudFileSystem myfileSystem, String name) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		log.info("Calling createRawFile on a CloudFileSystem: " + name);
		cloudFile = new AppEngineFile(myfileSystem.filesystem, name);
		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in createRawFile(CloudFileSystem, String) call, aborting");
			log.severe("Please call createNew or createRawFile call first!");
			return null;
		}
		return cloudFile;
	}
	
	public CloudFile createNewFile(String name) {
		try
		{
			sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
			log.info("Executing: " + sourceClass + "." + sourceMethod);

			log.info("Calling CloudFile.createNewFile with filename: " + name);
			FileService fileService = FileServiceFactory.getFileService();
			if (fileService == null)
			{
				log.severe("Unable to get the fileService from the FileServiceFactory for createNewFile: " + name);
				return null;
			}
			cloudFile =  fileService.createNewBlobFile(name);
			if (cloudFile == null)
			{
				log.severe("CloudFile is not valid in createNewFile call, aborting");
				log.severe("Please call createNew or createRawFile call first!");
				return null;
			}
			return this;
		} catch (IOException exception) {
			exception.getStackTrace();
			return null;
		} catch (Exception exception) {
			log.severe("General exception when calling createNewFile: ");
			log.severe(exception.getLocalizedMessage());
			return null;
		}
	}
	
	public CloudFile createNewTextFile() {
		try
		{
			sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
			log.info("Executing: " + sourceClass + "." + sourceMethod);
			FileService fileService = FileServiceFactory.getFileService();
			cloudFile =  fileService.createNewBlobFile("text/plain");
			return this;
		} catch (IOException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
			return null;
		}	catch (Exception exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
			return null;
		}
	}
	
	public void writeText(String value) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in writeText call, aborting");
			log.severe("Please call createNew or createRawFile call first!");
			return;
		}
		try {
			  // Open a channel to write to it
			  boolean lock = false;
			  FileService fileService = FileServiceFactory.getFileService();
			  if (fileService == null)
			  {	  
					log.severe("CloudFile.writeText fauled as unable to get the FileService");
					return;
			  }				  
			  FileWriteChannel writeChannel = fileService.openWriteChannel(cloudFile, lock);
			  writeChannel.close();
		} catch (FileNotFoundException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		} catch (LockException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		} catch (IOException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		}
	}
	
	public CloudFileSystem getFileSystem() {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in setposition call, aborting");
			return null;
		}
		if (cloudFileSystem == null) {
			cloudFileSystem = new CloudFileSystem();
			cloudFileSystem.filesystem = cloudFile.getFileSystem();
		}
		return cloudFileSystem;
	}
	
	public long getPosition() {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		pos = 0;
		log.info("CloudFile.getPosition() has been called!");
		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in setposition call, aborting");
			return -1;
		}
		try 
		{
				FileReadChannel channel = FileServiceFactory.getFileService().openReadChannel(cloudFile, true);
				pos = channel.position(); 
		} catch (FileNotFoundException exception) {
			log.severe(exception.getMessage());
		} catch (LockException exception) {
			log.severe(exception.getMessage());
		} catch (IOException exception) {
			log.severe(exception.getMessage());
		} catch (Exception exception) {
			log.severe(exception.getMessage());
		}	
		return pos;	
	}
	
	public void setPosition(long newPosition) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		pos = 0;
		log.info("CloudFile.setPosition() has been called!");
		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in setposition call, aborting");
			return;
		}
		try 
		{
			FileReadChannel channel = FileServiceFactory.getFileService().openReadChannel(cloudFile, true);
			if (channel == null )
			{
				log.severe("Unable to get the channel in CloudFile setPosition call");
			}
			channel.position(newPosition); 
			pos = newPosition;
		} catch (FileNotFoundException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		} catch (LockException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		} catch (IOException exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		} catch (Exception exception) {
			log.severe(exception.getMessage());
			log.severe(exception.getStackTrace().toString());
		}
	}
	
	public String getFullPath() {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in getFullPath call, aborting");
			return "";
		}
		log.info("CloudFile.getFullPath() has been called!");
		return cloudFile.getFullPath();
	}
	
	public String getNamePart() {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in getNamePart call, aborting");
			return "";
		}
		log.info("CloudFile.NamePart() has been called!");
		return cloudFile.getNamePart();
	}
	
	public String toSring() {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		if (cloudFile == null)
		{
			log.severe("CloudFile is not valid in toSring call, aborting");
			return "";
		}
		return cloudFile.toString();
	}
}
